package com.atlin.beaconsapiclientsdk.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.atlin.beaconsapiclientsdk.client.BeaconsApiClient;
import com.atlin.beaconsapiclientsdk.exception.BusinessException;
import com.atlin.beaconsapiclientsdk.exception.ErrorResponse;
import com.atlin.beaconsapiclientsdk.exception.ResponseCode;
import com.atlin.beaconsapiclientsdk.model.request.BaseRequest;
import com.atlin.beaconsapiclientsdk.model.request.WeatherRequest;
import com.atlin.beaconsapiclientsdk.model.response.ResultResponse;
import com.atlin.beaconsapiclientsdk.service.BeaconsApiService;
import com.atlin.beaconsapiclientsdk.util.SignUtil;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author atlin
 * @description
 * @createDate 2024/12/24 22:45
 */
@Data
@Slf4j
public class BeaconsApiServiceImpl implements BeaconsApiService {

    @Resource
    private BeaconsApiClient beaconsApiClient;

    /**
     * 网关地址
     */
    private String gatewayHost;

    @PostConstruct
    public void initHost() {
        this.gatewayHost = beaconsApiClient.getGatewayHost();
    }

    @Override
    public <O, T extends ResultResponse> T request(BaseRequest<O, T> request) throws BusinessException {
        try {
            return res(request);
        } catch (BusinessException e) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, e.getMessage());
        }
    }

    /**
     * 通用请求
     */
    @Override
    public <O, T extends ResultResponse> T request(BeaconsApiClient beaconsApiClient, BaseRequest<O, T> request) throws BusinessException {
        checkConfig(beaconsApiClient);
        return request(request);
    }

    @Override
    public ResultResponse getWeatherInfo(BeaconsApiClient beaconsApiClient, WeatherRequest request) throws BusinessException {
        return request(beaconsApiClient, request);
    }

    @Override
    public ResultResponse getWeatherInfo(WeatherRequest request) throws BusinessException {
        return request(request);
    }

    /**
     * 检查配置
     */
    public void checkConfig(BeaconsApiClient beaconsApiClient) {
        if (beaconsApiClient == null && this.getBeaconsApiClient() == null) {
            throw new BusinessException(ResponseCode.NO_AUTH_ERROR, "请检查AccessKey/SecretKey配置");
        }

        if (beaconsApiClient != null && !StringUtils.isAnyBlank(beaconsApiClient.getAccessKey(), beaconsApiClient.getSecretKey())) {
            this.setBeaconsApiClient(beaconsApiClient);
        }
    }

    /**
     * 执行请求
     */
    public <O, T extends ResultResponse> HttpResponse doRequest(BaseRequest<O, T> request) throws BusinessException {
        try (HttpResponse httpResponse = getHttpRequestByRequestMethod(request).execute()) {
            return httpResponse;
        } catch (Exception e) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, e.getMessage());
        }
    }


    /**
     * 通过请求方法获取http请求
     */
    public <O, T extends ResultResponse> HttpRequest getHttpRequestByRequestMethod(BaseRequest<O, T> request) throws BusinessException {
        if (ObjectUtils.isEmpty(request)) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, "请求参数错误");
        }
        String method = request.getMethod().trim().toUpperCase();
        String path = request.getPath().trim();

        if (StringUtils.isBlank(method)) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, "请求方法不存在");
        }
        if (StringUtils.isBlank(path)) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, "请求路径不存在");
        }

        log.info("【BeaconsApiService】请求方法：{}，请求路径：{}，请求参数：{}", method, path, request.getRequestParams());

        HttpRequest httpRequest;
        switch (method) {
            case "GET": {
                httpRequest = HttpRequest.get(splicingGetRequest(request, path));
                break;
            }
            case "POST": {
                httpRequest = HttpRequest.post(gatewayHost + path);
                break;
            }
            default:
                throw new BusinessException(ResponseCode.OPERATION_ERROR, "不支持的请求类型");
        }

        return httpRequest.addHeaders(getHeaders(JSONUtil.toJsonStr(request), beaconsApiClient))
                .body(JSONUtil.toJsonStr(request.getRequestParams()));
    }

    /**
     * 拼接Get请求
     */
    private <O, T extends ResultResponse> String splicingGetRequest(BaseRequest<O, T> request, String path) {
        StringBuilder urlBuilder = new StringBuilder(gatewayHost);
        // 在urlBuilder以 / 结尾 并且path以 / 开头的情况下 ，去除urlBuilder结尾的 /
        if (urlBuilder.toString().endsWith("/") && path.startsWith("/")) {
            urlBuilder.setLength(urlBuilder.length() - 1);
        }
        urlBuilder.append(path);
        if (!request.getRequestParams().isEmpty()) {
            urlBuilder.append("?");
            for (Map.Entry<String, Object> entry : request.getRequestParams().entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().toString();
                urlBuilder.append(key).append("=").append(value).append("&");
            }
            urlBuilder.setLength(urlBuilder.length() - 1);
        }
        log.info("【BeaconsApiService】请求URL：{}", urlBuilder);
        return urlBuilder.toString();
    }
    
    public <O, T extends ResultResponse> T res(BaseRequest<O, T> request) throws BusinessException {
        if (beaconsApiClient == null || StringUtils.isAnyBlank(beaconsApiClient.getAccessKey(), beaconsApiClient.getSecretKey())) {
            throw new BusinessException(ResponseCode.NO_AUTH_ERROR, "请先配置密钥AccessKey/SecretKey");
        }
        T res;
        try {
            Class<T> clazz = request.getResponseClass();
            res = clazz.newInstance();
        } catch (Exception e) {
            throw new BusinessException(ResponseCode.OPERATION_ERROR, e.getMessage());
        }
        Map<String, Object> data;

        try (HttpResponse httpResponse = doRequest(request)) {
            String body = httpResponse.body();
            data = new HashMap<>();

            if (httpResponse.getStatus() != 200) {
                ErrorResponse errorResponse = JSONUtil.toBean(body, ErrorResponse.class);
                data.put("code", errorResponse.getCode());
                data.put("errorMessage", errorResponse.getMessage());
            } else {
                try {
                    // 解析对象
                    data = new Gson().fromJson(body, new TypeToken<Map<String, Object>>() {
                    }.getType());
                } catch (JsonSyntaxException e) {
                    // 解析失败，作为普通字符串处理
                    data.put("value", body);
                }
            }

        }
        res.setData(data);
        return res;
    }

    /**
     * 构造请求头
     *
     * @param body
     * @param beaconsApiClient
     * @return {@link Map}
     */
    private Map<String, String> getHeaders(String body, BeaconsApiClient beaconsApiClient) {
        HashMap<String, String> hashMap = new HashMap<>(4);
        hashMap.put("accessKey", beaconsApiClient.getAccessKey());
        String encodedBody = SecureUtil.md5(body);
        hashMap.put("body", encodedBody);
        hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        hashMap.put("sign", SignUtil.genSign(encodedBody, beaconsApiClient.getSecretKey()));

        return hashMap;
    }
}
